'use strict';
const BaseService = require('./base');

const StringUtil = require('../utils/StringUtil');
const HelperUtil = require('../utils/HelperUtil');
const ResponseUtil = require('../utils/ResponseUtil');
const VRCE = require('../utils/ViewResultCodeEnum');
const RCEM = require('../utils/ResultCodeEnumMsg');

class OrderService extends BaseService {

    async getBuyMargin(orderId, conn) {
        let sql = 'select * from t_order_margin where order_id=? and valid=1 and back_status=0 and status=1 and type=1';
        let result = await this.executeSqlFirst(sql, [orderId], conn);
        return result;
    }

    async getSellMargin(goodsId, conn) {
        let sql = 'select * from t_order_margin where goods_id=? and valid=1 and back_status=0 and status=1 and type=0';
        let result = await this.executeSqlFirst(sql, [goodsId], conn);
        return result;
    }

    async backMargin(margin, conn) {
        let payMode = margin.payMode;

        if (payMode === PayMode.BALANCE) {//如果是余额支付
            //加卖家可用
            let changeParams = {
                userId: margin['userId'], amount: margin['price'], frozen: -margin['price']
            };
            let size = await this.ctx.service.balance.changeBalance(changeParams, conn);
            if (size <= 0) {
                return {
                    code: 500,
                    message: `更新资产失败 userId=${margin['userId']},marginId=${margin.id}`
                }
            }

            let sql = 'update t_order_margin set back_status=1 where id=? ';
            size = await this.executeSqlSucc(sql, [margin['id']], conn);
            if (size <= 0) {
                return {
                    code: 500,
                    message: '更新保证金信息失败'
                }
            }

            let poolParams = {
                margin_id: margin.id,
                status: 1
            };
            let insertResult = await this.executeInsert('t_order_margin_back_pool', poolParams, conn);
            if (!insertResult.affectedRows) {
                return {
                    code: 500,
                    message: '新增保证金池子记录失败'
                }
            }

            let marginRecordParams = {
                id: StringUtil.getUUIDV2(),
                margin_id: margin.id,
                pay_mode: margin.payMode,
                back_status: 1
            };
            let insertMarginRecordResult = await this.executeInsert('t_order_margin_record', marginRecordParams, conn);

            if (!insertMarginRecordResult.affectedRows) {
                throw Error('添加保证金记录失败2')
            }

            let balanceParams = {
                userId: margin['userId'],
                type: margin.type == 0 ? BalanceDetailType.PUBLISH_GOODS[0] : BalanceDetailType.ORDER_BIDDING_AUCTION[0],
                typeRemark: margin.type == 0 ? BalanceDetailType.PUBLISH_GOODS[1] : BalanceDetailType.ORDER_BIDDING_AUCTION[1],
                balanceRemark: margin.type == 0 ? '发布商品退回保证金' : '订单交易退回保证金',
                tranType: 'in',
                payMode: payMode,
                amount: margin['price'],
                feeRate: 0,
                feeAmount: 0,
                totalAmount: margin['price'],
                refId: margin['id']
            };
            size = await this.ctx.service.balance.insertBalanceDetail(balanceParams, conn);
            if (size <= 0) {
                throw Error('插入资金详情记录失败')
            }

            return {
                code: 200,
                message: 'ok'
            }

        } else if (payMode === PayMode.MARGIN) {//预存保证金支付
            let changeParams = {
                userId: margin['userId'], amount: margin['price'], frozen: -margin['price']
            };
            let size = await this.ctx.service.balance.changeMarginBalance(changeParams, conn);
            if (size <= 0) {
                return {
                    code: 500,
                    message: `更新资产失败 userId=${margin['userId']},marginId=${margin.id}`
                }
            }

            let sql = 'update t_order_margin set back_status=1 where id=? ';
            size = await this.executeSqlSucc(sql, [margin['id']], conn);
            if (size <= 0) {
                return {
                    code: 500,
                    message: '更新保证金信息失败'
                }
            }

            let poolParams = {
                margin_id: margin.id,
                status: 1
            };
            let insertResult = await this.executeInsert('t_order_margin_back_pool', poolParams, conn);
            if (!insertResult.affectedRows) {
                return {
                    code: 500,
                    message: '新增保证金池子记录失败'
                }
            }

            let marginRecordParams = {
                id: StringUtil.getUUIDV2(),
                margin_id: margin.id,
                pay_mode: margin.payMode,
                back_status: 1
            };
            let insertMarginRecordResult = await this.executeInsert('t_order_margin_record', marginRecordParams, conn);

            if (!insertMarginRecordResult.affectedRows) {
                throw Error('添加保证金记录失败2')
            }

            let balanceParams = {
                userId: margin['userId'],
                type: margin.type == 0 ? BalanceDetailType.PUBLISH_GOODS[0] : BalanceDetailType.ORDER_BIDDING_AUCTION[0],
                typeRemark: margin.type == 0 ? BalanceDetailType.PUBLISH_GOODS[1] : BalanceDetailType.ORDER_BIDDING_AUCTION[1],
                balanceRemark: margin.type == 0 ? '发布商品退回保证金' : '订单交易退回保证金',
                tranType: 'in',
                payMode: payMode,
                amount: margin['price'],
                feeRate: 0,
                feeAmount: 0,
                totalAmount: margin['price'],
                refId: margin['id']
            };
            size = await this.ctx.service.balance.insertBalanceDetail(balanceParams, conn);
            if (size <= 0) {
                throw Error('插入资金详情记录失败')
            }


            return {
                code: 200,
                message: 'ok'
            }
        }
        else if (payMode === PayMode.WECHAT) {//如果是微信支付

            try {
                if(margin && margin.remark === '易宝支付'){
                    await this.ctx.service.aggPay.refundAmountByAggApp({
                        outTradeNo: margin['wxOrderId'],
                        refundFee: margin.price,
                        totalFee: margin.price,
                        refundDesc: '退款-保证金'
                    })
                }else{
                    await this.ctx.service.wechatPay.refundAmountByWxApp({
                        outTradeNo: margin['wxOrderId'],
                        refundFee: margin.price,
                        totalFee: margin.price,
                        refundDesc: '退款-保证金'
                    })
                }
            } catch (e) {
                this.ctx.app.logger.error('confirmOrderGoods error', e.message);
                console.error('confirmOrderGoods error', e.message);
                return {
                    code: 500,
                    message: '微信退款失败'
                }
            }

            let changeParams = {
                userId: margin['userId'], amount: 0, frozen: -margin['price']
            };
            let size = await this.ctx.service.balance.changeBalance(changeParams, conn);
            if (size <= 0) {
                return {
                    code: 500,
                    message: `更新资产失败 userId=${margin['userId']},marginId=${margin.id}`
                }
            }

            let sql = 'update t_order_margin set back_status=1 where id=? ';
            size = await this.executeSqlSucc(sql, [margin['id']], conn);
            if (size <= 0) {
                return {
                    code: 500,
                    message: '更新保证金信息失败'
                }
            }

            let poolParams = {
                margin_id: margin.id,
                status: 1
            };
            let insertResult = await this.executeInsert('t_order_margin_back_pool', poolParams, conn);
            if (!insertResult.affectedRows) {
                return {
                    code: 500,
                    message: '新增保证金池子记录失败'
                }
            }

            let marginRecordParams = {
                id: StringUtil.getUUIDV2(),
                margin_id: margin.id,
                pay_mode: margin.payMode,
                back_status: 1
            };
            let insertMarginRecordResult = await this.executeInsert('t_order_margin_record', marginRecordParams, conn);

            if (!insertMarginRecordResult.affectedRows) {
                throw Error('添加保证金记录失败2')
            }

            let balanceParams = {
                userId: margin['userId'],
                type: margin.type == 0 ? BalanceDetailType.PUBLISH_GOODS[0] : BalanceDetailType.ORDER_BIDDING_AUCTION[0],
                typeRemark: margin.type == 0 ? BalanceDetailType.PUBLISH_GOODS[1] : BalanceDetailType.ORDER_BIDDING_AUCTION[1],
                balanceRemark: margin.type == 0 ? '发布商品退回保证金' : '订单交易退回保证金',
                tranType: 'in',
                payMode: payMode,
                amount: margin['price'],
                feeRate: 0,
                feeAmount: 0,
                totalAmount: margin['price'],
                refId: margin['id']
            };
            size = await this.ctx.service.balance.insertBalanceDetail(balanceParams, conn);
            if (size <= 0) {
                throw Error('插入资金详情记录失败')
            }

            return {
                code: 200,
                message: 'ok'
            }


        } else if (payMode === PayMode.ALIPAY) {//暂不支持
            return {
                code: 500,
                message: '暂不支持支付宝'
            }
        }
    }


    //罚没保证金
    async forfeitMargin(margin, orderId, oper, $deductRate, conn) {

        let goods = await this.ctx.service.goods.selectPureByPrimaryKey(margin['goodsId']);
        let order = await this.ctx.service.order.selectPureByPrimaryKey(orderId);
        let payMode = margin.payMode;
        let deductRate = 0.5;
        if ($deductRate != null) {
            deductRate = $deductRate;
        }

        const GETPrice = HelperUtil.bigNumberMultipliedBy(margin.price, deductRate);
        const platformPrice = HelperUtil.bigNumberMinus(margin.price, GETPrice);

        let sql = 'update t_order_margin set back_status=2,deduct_rate=?,sell_price=?,platform_price=?,deduct_source=?,deduct_source_remark=? where id=? ';
        if (oper === 'sell') {
            sql = 'update t_order_margin set back_status=2,deduct_rate=?,buy_price=?,platform_price=?,deduct_source=?,deduct_source_remark=? where id=? ';
        }
        await this.executeSqlSucc(sql, [deductRate, GETPrice, platformPrice, DeductSource.OrderTimeout[0], DeductSource.OrderTimeout[1], margin.id], conn);
        let marginPrice = margin.price;

        let isBuy = oper === 'buy' ? true : false;
        let changeParams = {
            userId: isBuy ? goods.userId : order.userId,//买家操作，罚没买家，卖家分钱;否则卖家操作，则罚没卖家，买家分钱
            amount: HelperUtil.bigNumberMultipliedBy(marginPrice, deductRate),
            frozen: 0
        };
        if (deductRate != 0) {
            let size = await this.ctx.service.balance.changeBalance(changeParams, conn);
            if (size <= 0) {
                return {
                    code: 500,
                    message: '更新卖家资产失败'
                }
            }
        }

        //资金详情
        if (deductRate != 0) {
            let balanceParams = {
                userId: isBuy ? goods.userId : order.userId,
                type: BalanceDetailType.CANCEL_ORDER_MARGIN[0],
                typeRemark: BalanceDetailType.CANCEL_ORDER_MARGIN[1],
                balanceRemark: isBuy ? '买家超时未支付订单保证金' : '平台补偿',
                tranType: 'in',
                payMode: PayMode.BALANCE,
                amount: HelperUtil.bigNumberMultipliedBy(marginPrice, deductRate),
                feeRate: 0,
                feeAmount: 0,
                totalAmount: HelperUtil.bigNumberMultipliedBy(marginPrice, deductRate),
                refId: orderId,
                status: 1
            };
            let size = await this.ctx.service.balance.insertBalanceDetail(balanceParams, conn);
            if (size <= 0) {
                return {
                    code: 500,
                    message: '插入资金详情记录失败'
                }
            }
        }


        let marginRecordParams = {
            id: StringUtil.getUUIDV2(),
            margin_id: margin.id,
            pay_mode: margin.payMode,
            back_status: 2
        };
        let insertMarginRecordResult = await this.executeInsert('t_order_margin_record', marginRecordParams, conn);

        if (!insertMarginRecordResult.affectedRows) {
            return {
                code: 500,
                message: '添加保证金记录失败2'
            }
        }

        let poolParams = {
            margin_id: margin.id,
            status: 2
        };
        let insertPoolResult = await this.executeInsert('t_order_margin_back_pool', poolParams, conn);
        if (!insertPoolResult.affectedRows) {
            return {
                code: 500,
                message: '新增保证金池子记录失败'
            }
        }

        if (payMode === PayMode.BALANCE) {
            //减去冻结 罚没
            let changeParams2 = {
                userId: isBuy ? order.userId : goods.userId, amount: 0, frozen: -margin.price
            };
            let size = await this.ctx.service.balance.changeBalance(changeParams2, conn);
            if (size <= 0) {
                return {
                    code: 500,
                    message: '更新余额失败，可能余额不足'
                }
            }
        } else if (payMode === PayMode.MARGIN) {
            let changeParams = {
                userId: isBuy ? order.userId : goods.userId, amount: 0, frozen: -margin.price
            };
            let size = await this.ctx.service.balance.changeMarginBalance(changeParams, conn);
            if (size <= 0) {
                return {
                    code: 500,
                    message: '更新资产失败'
                }
            }
        } else if (payMode === PayMode.WECHAT) {
            //减去冻结 罚没
            let changeParams2 = {
                userId: isBuy ? order.userId : goods.userId, amount: 0, frozen: -margin.price
            };
            let size = await this.ctx.service.balance.changeBalance(changeParams2, conn);
            if (size <= 0) {
                return {
                    code: 500,
                    message: '更新余额失败，可能余额不足'
                }
            }
        } else if (payMode === PayMode.ALIPAY) {
            return {
                code: 500,
                message: '暂不支持支付宝'
            }
        }

        //资金记录
        let balanceParams2 = {
            userId: isBuy ? order.userId : goods.userId,//记录罚没人的资金记录
            type: margin.type === 0 ? BalanceDetailType.CANCEL_ORDER_MARGIN[0] : BalanceDetailType.CANCEL_ORDER_MARGIN[0],
            typeRemark: margin.type === 0 ? BalanceDetailType.CANCEL_ORDER_MARGIN[1] : BalanceDetailType.CANCEL_ORDER_MARGIN[1],
            balanceRemark: margin.type === 0 ? '发布商品微信支付保证金' : '竞价商品保证金微信支付',
            tranType: 'out',
            amount: margin.price,
            payMode: margin.payMode,
            feeRate: 0,
            feeAmount: 0,
            totalAmount: margin.price,
            refId: orderId,
            status: 1
        };
        let size = await this.ctx.service.balance.insertBalanceDetail(balanceParams2, conn);
        if (size <= 0) {
            return {
                code: 500,
                message: '插入资金详情记录失败'
            }
        }

        return {
            code: 200,
            message: 'ok',
            amount: changeParams.amount,
            marginPrice: marginPrice,
            GETPrice: GETPrice
        }
    }


    async selectPureByPrimaryKey(orderId, conn) {
        let sql = 'select * from t_order where id=? ';
        let result = await this.executeSqlFirst(sql, [orderId], conn);
        return result;
    }

    async selectTicket(orderId, conn) {
        let sql = 'select * from t_order_ticket where order_id=? and valid=1';
        let result = await this.executeSqlFirst(sql, [orderId], conn);
        return result;
    }

    async selectCommentTime(orderId, conn) {
        let sql = 'select * from t_order_comment where order_id=? and valid=1 order by create_time asc limit 1';
        let result = await this.executeSqlFirst(sql, [orderId], conn);
        return result ? result.createTime : null
    }

    async getOrderList({goodsType, keyword, orderStatus, afterSale, pageNum, pageSize, orderId}) {

        let sql = `
                    SELECT SQL_CALC_FOUND_ROWS
                        A.id AS order_id,
                        A.goods_id,
                        A.pay_price AS order_pay_price,
                        A.post_fee,
                        A.address_id,
                        A.address_user_name,
                        A.address_user_phone,
                        A.address_user_area,
                        A.address_user_detail_address,
                        A.create_time,
                        A.pay_time,
                        A.pay_complete_time,
                        A.step_bidding_price,
                        A.status as order_status,
                        B.avatar_url AS user_avatar,
                        B.NAME AS user_name,
                        B.id AS user_id,
                        B.user_no,
                        C.head_img AS goods_head_img,
                        C.NAME AS goods_name,
                        C.goods_type,
                    IF
                        (
                            C.goods_type = 0,
                            C.limit_price,
                            C.init_price 
                        ) AS goods_price,
                        C.integral_price AS goods_integral_price
                    FROM
                        t_order A
                        INNER JOIN t_user B ON A.user_id = B.id
                        LEFT JOIN t_shop_goods C ON A.goods_id = C.id
                        WHERE A.valid = 1
                  `;

        let orderAfterSaleMap = {
            0: 10,
            1: 11,
            2: 12,
            8: 13,
            9: 14
        };

        let orderAfterSaleMap2 = {
            '10': 0,
            '11': 1,
            '12': 2,
            '13': 8,
            '14': 9
        };

        let wheres = [
            {column: 'goods_type', value: goodsType, options: {tname: 'C'}},
            {column: 'id', value: orderId, options: {tname: 'C'}}
        ];

        let formatSqlResult = this.formatSqlWhere(sql, wheres);

        sql = formatSqlResult[0];

        let options = formatSqlResult[1];

        if (afterSale === 1) {//售后订单
            if (orderStatus) {
                sql += ` AND EXISTS(SELECT 1 FROM t_order_after_sale T1 WHERE T1.order_id=A.id AND T1.status=? )`;
                options.push(orderAfterSaleMap2[orderStatus]);
            } else {
                sql += ` AND EXISTS(SELECT 1 FROM t_order_after_sale T1 WHERE T1.order_id=A.id AND T1.status<>9 )`
            }
        } else {
            sql += ` AND NOT EXISTS(SELECT 1 FROM t_order_after_sale T1 WHERE T1.order_id=A.id AND T1.status<>9 )`;
            if (orderStatus) {
                sql += ` AND A.status=?`;
                options.push(orderStatus);
            }
        }

        if (keyword) {
            sql += ' AND(A.id=? OR B.user_no=? OR B.id=? ) ';
            options.push(keyword);
            options.push(keyword);
            options.push(keyword);
        }

        if (afterSale === 1) {//售后订单
            sql += " order by A.after_sale_time,A.create_time desc ";
        } else {
            sql += " order by A.create_time desc ";
        }
        sql = this.addMysqlPageSize(sql, pageNum, pageSize);
        let result = await this.queryPageData(sql, options);

        let list = result.list;

        await Promise.all(list.map(async (item) => {
            //发货时间
            let ticket = await this.selectTicket(item.orderId);
            item.ticketTime = ticket ? ticket.createTime : null;

            let ticketInfo = await this.getOrderTicketList(item.orderId);
            item.ticketInfo = ticketInfo;

            //评价时间
            let commentTime = await this.selectCommentTime(item.orderId);
            item.commentTime = commentTime;

            //order_pay_price post_fee
            item.orderSumPayPrice = HelperUtil.bigNumberPlus(item['orderPayPrice'] || 0, item['postFee'] || 0);

            if (afterSale === 1) {//售后订单
                let sql = 'SELECT * FROM t_order_after_sale T1 WHERE T1.order_id=? AND T1.status<>9 order by create_time desc limit 1';
                let orderAfterSale = await this.executeSqlFirst(sql, [item.orderId]);
                if (orderAfterSale) {
                    item.orderStatus = orderAfterSaleMap[orderAfterSale.status];
                }
                item.orderAfterSale = orderAfterSale;
            } else {
                let sql = 'SELECT * FROM t_order_after_sale T1 WHERE T1.order_id=? AND T1.status<>9 order by create_time desc limit 1';
                let orderAfterSale = await this.executeSqlFirst(sql, [item.orderId]);
                item.orderAfterSale = orderAfterSale;
            }
        }));

        return result;
    }


    async getOrderCommentList({orderId, orderStatus, pageNum, pageSize}) {

        let sql = `
                    SELECT SQL_CALC_FOUND_ROWS
                        A.id AS order_id,
                        A.goods_id,
                        A.pay_price AS order_pay_price,
                        A.post_fee,
                        A.address_id,
                        A.address_user_name,
                        A.address_user_phone,
                        A.address_user_area,
                        A.address_user_detail_address,
                        A.create_time,
                        A.goods_complete_time,
                        A.pay_time,
                        A.pay_complete_time,
                        A.status as order_status ,
                        B.avatar_url AS user_avatar,
                        B.NAME AS user_name,
                        B.id AS user_id,
                        C.head_img AS goods_head_img,
                        C.NAME AS goods_name,
                    IF
                        (
                            C.goods_type = 0,
                            C.limit_price,
                            C.init_price 
                        ) AS goods_price,
                        C.integral_price AS goods_integral_price,
                        M.id as comment_id,
                        M.star_level as comment_star_level,
                        M.content as comment_content,
                        M.create_time as comment_create_time
                    FROM
                        t_order A
                        INNER JOIN t_order_comment M ON A.id=M.order_id
                        INNER JOIN t_user B ON A.user_id = B.id
                        LEFT JOIN t_shop_goods C ON A.goods_id = C.id
                        WHERE A.valid = 1 AND M.valid=1
                  `;


        let wheres = [
            {column: 'id', value: orderId, options: {tname: 'A'}},
        ];

        let formatSqlResult = this.formatSqlWhere(sql, wheres);

        sql = formatSqlResult[0];

        let options = formatSqlResult[1];

        sql += " order by M.create_time desc ";
        sql = this.addMysqlPageSize(sql, pageNum, pageSize);
        let result = await this.queryPageData(sql, options);

        let list = result.list;

        await Promise.all(list.map(async (item) => {
            //发货时间
            let ticket = await this.selectTicket(item.orderId);
            item.ticketTime = ticket ? ticket.createTime : null;

            //评价时间
            let commentTime = await this.selectCommentTime(item.orderId);
            item.commentTime = commentTime;

        }));

        return result;
    }


    async deleteOrderComment() {
        let commentId = this.ctx.params.commentId;

        let sql = 'update t_order_comment set valid=0 where id=? ';
        await this.executeSqlSucc(sql, [commentId]);

        return commentId;
    }


    async getOrderTicketList($orderId) {
        let {orderId} = this.ctx.query;
        if ($orderId) {
            orderId = $orderId;
        }
        if (!orderId) {
            return ResponseUtil.retArgErr();
        }

        let sql = 'SELECT B.content,B.ticket_time,B.status FROM t_order_ticket A INNER JOIN t_order_ticket_info B ON A.ticket = B.ticket WHERE A.valid=1 AND A.order_id=? AND B.valid = 1 ORDER BY B.ticket_time desc';
        let result = await this.executeSql(sql, [orderId]);

        sql = 'select * from t_order_ticket where order_id=? and valid=1 ';
        let ticket = await this.executeSqlFirst(sql, [orderId]);
        if (ticket) {
            result.push({
                content: '包裹正在等待揽收',
                ticket_time: ticket.createTime,
                status: 1
            })
        }

        sql = 'select * from t_order where id=? ';
        let order = await this.executeSqlFirst(sql, [orderId]);
        if (order) {
            result.push({
                content: '商品已经下单',
                ticket_time: order.createTime,
                status: 0
            })
        }

        return {
            ticketList: result,
            addressInfo: {
                addressId: order ? order.addressId : null,
                addressUserName: order ? order.addressUserName : null,
                addressUserPhone: order ? order.addressUserPhone : null,
                addressUserArea: order ? order.addressUserArea : null,
                addressUserDetailAddress: order ? order.addressUserDetailAddress : null
            },
            ticketInfo: {
                company: ticket ? ticket.company : null,
                ticket: ticket ? ticket.ticket : null
            }
        };
    }


    async orderConfirmDelivery() {
        let {orderId, company, ticket} = this.ctx.request.body;

        let loginUserInfo = this.ctx.getLoginInfo();
        let operatorType = loginUserInfo.operatorType;
        let operatorId = loginUserInfo.operatorId;
        let createBy = loginUserInfo.createBy;

        if (!orderId || !company || !ticket) {
            return ResponseUtil.retArgErr();
        }

        //todo 验证快递公司与快递单号是否匹配

        let order = await this.selectPureByPrimaryKey(orderId);
        if (!order) {
            return ResponseUtil.resError(VRCE.NOT_EXIST_ORDER[1], VRCE.NOT_EXIST_ORDER[0]);
        }

        let sql = 'select * from t_order_ticket where order_id=? and valid=1 ';
        let exist = await this.executeSqlFirst(sql, [orderId]);
        if (exist) {
            return ResponseUtil.resError(VRCE.ORDER_SEND[1], VRCE.ORDER_SEND[0]);
        }


        if (order.status !== 1) {
            return ResponseUtil.resError(VRCE.ORDER_UNPAY[1], VRCE.ORDER_UNPAY[0]);
        }

        let goods = await this.ctx.service.goods.selectPureByPrimaryKey(order['goodsId']);
        if (!goods || goods.delFlag != 0 || goods.valid != 1) {
            return ResponseUtil.resError(VRCE.NOT_EXIST_GOODS[1], VRCE.NOT_EXIST_GOODS[0]);
        }
        if (goods.userId != operatorId) {
            return ResponseUtil.resError(RCEM.NO_PERMISSION[1], RCEM.NO_PERMISSION[0]);
        }


        let conn = await this.app.mysql.beginTransaction();

        try {

            let params = {
                id: StringUtil.getUUIDV2(),
                order_id: orderId,
                company: company,
                ticket: ticket
            };

            let insertResult = await this.executeInsert('t_order_ticket', params, conn);
            if (!insertResult.affectedRows) {
                throw Error('添加快递单号失败');
            }

            let sql = 'update t_order set status=? where id=? ';
            let size = await this.executeSqlSucc(sql, [2, orderId], conn);
            if (size <= 0) {
                throw Error('更新订单失败');
            }

            await conn.commit();

            return orderId;

        } catch (e) {
            this.ctx.app.logger.info('orderConfirmDelivery error', e.message);
            await conn.rollback();
            throw Error('服务器错误')
        }
    }


    //退款中与买家已拒绝都可以操作
    async findOneUntreatedOrderAfterSaleByOrderId(orderId) {
        let sql = 'select * from t_order_after_sale where status=0 and order_id=? order by create_time desc limit 1';
        let result = await this.executeSqlFirst(sql, [orderId]);
        return result;
    }

    async orderRefusalRefund() {
        let {orderId} = this.ctx.request.body;

        let loginUserInfo = this.ctx.getLoginInfo();
        let operatorType = loginUserInfo.operatorType;
        let operatorId = loginUserInfo.operatorId;
        let createBy = loginUserInfo.createBy;

        if (!orderId) {
            return ResponseUtil.retArgErr();
        }
        let order = await this.selectPureByPrimaryKey(orderId);
        if (!order) {
            return ResponseUtil.resError('no such order');
        }
        let object = await this.findOneUntreatedOrderAfterSaleByOrderId(orderId);
        if (!object) {
            return ResponseUtil.resError('该退款已处理过啦');
        }

        let conn = await this.app.mysql.beginTransaction();
        try {

            let sql = 'update t_order_after_sale set status=2,affirm_by=?,affirm_by_id=?,affirm_source=1,affirm_time=NOW() where id=? ';
            let size = await this.executeSqlSucc(sql, [createBy, operatorId, object.id], conn);
            if (size <= 0) {
                throw Error('更新退款状态失败');
            }

            let recordParams = {
                order_id: orderId,
                order_after_sale_id: object.id,
                status: 2,
                affirm_by: createBy,
                affirm_by_id: operatorId,
                affirm_source: 1
            };

            let insertResult = await this.executeInsert('t_order_after_sale_audit_record', recordParams, conn);
            if (!insertResult.affectedRows) {
                throw Error('添加退款审核记录失败');
            }


            let user = await this.ctx.service.user.selectPureByPrimaryKey(order.userId);
            if (user && user.openid) {
                let goods = this.ctx.service.goods.selectPureByPrimaryKey(order.goodsId);
                let messageParams = {
                    touser: user.openid,
                    goodsName: goods ? goods.name : '',
                    afterSaleType: '退货退款',
                    statusText: '商家拒绝退款',
                    remark: '商家拒绝退款',
                    page: '/pagesSub/pages/my-bought/my-bought?tab=4'
                };
                this.ctx.service.wechat.sendOrderAfterSaleMessage(messageParams);
            }

            await conn.commit();
            return 1;

        } catch (e) {
            this.ctx.app.logger.info('orderRefusalRefund error', e.message);
            await conn.rollback();
            throw Error('服务器错误')
        }
    }

    async getSellOpenIdByOrderId(orderId) {
        let sql = 'select c.openid from t_order a inner join t_shop_goods b on a.goods_id=b.id inner join t_user c on b.user_id=c.id where a.id=? ';
        let result = await this.executeSqlFirst(sql, [orderId]);
        return result ? result.openid : null;
    }

    async getBuyOpenIdByOrderId(orderId) {
        let sql = 'select b.openid from t_order a inner join t_user b on a.user_id=b.id where a.id=? ';
        let result = await this.executeSqlFirst(sql, [orderId]);
        return result ? result.openid : null;
    }


    async orderConfirmRefund($body) {
        let {orderId, $remark, deductOpposite} = $body || this.ctx.request.body;


        let loginUserInfo = this.ctx.getLoginInfo();
        let operatorType = loginUserInfo.operatorType;
        let operatorId = loginUserInfo.operatorId;
        let createBy = loginUserInfo.createBy;

        if (!orderId) {
            return ResponseUtil.retArgErr();
        }
        let object = await this.findOneUntreatedOrderAfterSaleByOrderId(orderId);
        if (!object) {
            return ResponseUtil.resError('该退款已处理过啦');
        }
        let orderAfterSale = object;

        let order = await this.selectPureByPrimaryKey(orderId);
        if (!order || order.valid === 0 || order.delFlag === 1) {
            return ResponseUtil.resError(VRCE.ORDER_NOT_EXIST[1], VRCE.ORDER_NOT_EXIST[1]);
        }

        if (![1, 2].includes(order.status)) {
            return ResponseUtil.resError(VRCE.ORDER_UNPAY[1], VRCE.ORDER_UNPAY[0]);
        }

        let goods = await this.ctx.service.goods.selectPureByPrimaryKey(order.goodsId);
        if (!goods) {
            return ResponseUtil.resError(VRCE.NOT_EXIST_GOODS[1], VRCE.NOT_EXIST_GOODS[0]);
        }

        if (goods.goodsType == 1) {
            if (!['SELLER', 'BUYER', 'NONE'].includes(deductOpposite)) {
                return ResponseUtil.resError('deductOpposite is require');
            }
        }

        let conn = await this.app.mysql.beginTransaction();

        try {
            //减去卖家冻结 已发货，不扣快递费；未发货，扣快递费
            //返回买家金额 已发货，不退快递费；未发货，退快递费
            //更新订单收款金额
            //买/卖家资金详情
            //资金详情状态更改
            //更新退款申请
            //一口价商品都不扣除保证金
            //扣除哪一方的保证金
            //扣卖家保证金时 退买家保证金 竞拍商品下架；扣买家保证金时 不退卖家保证金 竞拍商品下架
            //商品数量更新

            const payPrice = order.payPrice;
            const postFee = order.postFee;
            const sumPrice = HelperUtil.bigNumberPlus(payPrice, postFee);
            let diffPrice = order.deliverGoodsMode == 1 ? HelperUtil.bigNumberMinus(order['curSellPrice'], postFee) : order['curSellPrice'];
            if (order.status === 1) {//还未发货的 退回收到的金额，包括快递费
                diffPrice = order['curSellPrice']
            }
            //看看是不是补差价 补差价不用退快递费 如是补差价，需要更改订单curSellPrice的数值 curSellPrice-priceAdjAmount
            if (orderAfterSale.refundReasonId === 'PriceAdj') {
                if (orderAfterSale.priceAdjAmount <= 0) {
                    throw Error('差价金额异常')
                }
                diffPrice = orderAfterSale.priceAdjAmount;
            }

            if (diffPrice < 0) {
                throw Error('退款金额异常')
            }

            //减去卖家冻结
            if (order.status === 3) {
                let changeParams = {
                    userId: goods.userId, amount: -diffPrice, frozen: 0
                };
                const size = await this.ctx.service.balance.changeBalance(changeParams, conn);
                if (size <= 0) {
                    throw Error('更新卖家余额失败，可能余额不足')
                }
            } else {
                let changeParams = {
                    userId: goods.userId, amount: 0, frozen: -diffPrice
                };
                const size = await this.ctx.service.balance.changeBalance(changeParams, conn);
                if (size <= 0) {
                    throw Error('更新卖家余额失败，可能余额不足')
                }

                if (order.deliverGoodsMode == 1 && order.status === 2) {//已发货时
                    //当为冻结时 将快递非从冻结转化成可用
                    let changeParams2 = {
                        userId: goods.userId, amount: postFee, frozen: -postFee
                    };
                    const size2 = await this.ctx.service.balance.changeBalance(changeParams2, conn);
                    if (size2 <= 0) {
                        throw Error('更新卖家余额失败，可能余额不足')
                    }
                }
            }


            //更新订单收款金额 不差价时 减去补的差价
            if (orderAfterSale.refundReasonId === 'PriceAdj') {
                let sql = 'update t_order set curSellPrice=? where id=? ';
                let leftAmount = HelperUtil.bigNumberMinus(order.curSellPrice, orderAfterSale.priceAdjAmount);
                if (leftAmount <= 0) {
                    throw Error('差价金额异常')
                }
                let size = await this.executeSqlSucc(sql, [leftAmount, order.id], conn);
                if (size <= 0) {
                    throw Error('更新差价金额异常')
                }
            }


            //卖家资金详情
            let sellBalanceParams = {
                userId: goods.userId,
                type: goods.goodsType === 1 ? BalanceDetailType.ORDER_BIDDING[0] : BalanceDetailType.ORDER_BUYNOW[0],
                typeRemark: goods.goodsType === 1 ? BalanceDetailType.ORDER_BIDDING[1] : BalanceDetailType.ORDER_BUYNOW[1],
                balanceRemark: '买家申请商品退款成功',
                tranType: 'out',
                payMode: PayMode.BALANCE,
                amount: diffPrice,
                feeRate: 0,
                feeAmount: 0,
                totalAmount: diffPrice,
                refId: orderId,
                status: 1
            };
            let size = await this.ctx.service.balance.insertBalanceDetail(sellBalanceParams, conn);
            if (size <= 0) {
                throw Error('插入资金详情记录失败')
            }


            //买家资金详情
            let buyBalanceParams = {
                userId: order.userId,
                type: goods.goodsType === 1 ? BalanceDetailType.ORDER_BIDDING[0] : BalanceDetailType.ORDER_BUYNOW[0],
                typeRemark: goods.goodsType === 1 ? BalanceDetailType.ORDER_BIDDING[1] : BalanceDetailType.ORDER_BUYNOW[1],
                balanceRemark: '商品退款成功',
                tranType: 'in',
                payMode: order.payMode,
                amount: order.status === 1 ? sumPrice : order.payPrice,
                feeRate: 0,
                feeAmount: 0,
                totalAmount: order.status === 1 ? sumPrice : order.payPrice,
                refId: orderId,
                status: 1
            };
            if (orderAfterSale.refundReasonId === 'PriceAdj') {//补差价金额
                buyBalanceParams.amount = orderAfterSale.priceAdjAmount;
                buyBalanceParams.totalAmount = orderAfterSale.priceAdjAmount;
            }
            size = await this.ctx.service.balance.insertBalanceDetail(buyBalanceParams, conn);
            if (size <= 0) {
                throw Error('插入资金详情记录失败')
            }


            //资金详情状态更改 卖家与买家
            let sql = 'select * from t_balance_detail where ref_id=? and (type="order_buynow" or type="order_bidding")';
            let detailList = await this.executeSql(sql, [orderId], conn);
            for (let i = 0; i < detailList.length; i++) {
                let sql = 'update t_balance_detail set status=2 where id=?';
                let size = await this.executeSqlSucc(sql, [detailList[i].id], conn);
                if (size <= 0) {
                    throw Error('更改资金记录失败')
                }
            }

            //更新退款申请
            let isRefundFullPrice = 0;
            let isRefundPostFee = 0;
            if (order.status === 1 && orderAfterSale.refundReasonId != 'PriceAdj') {//未发货
                isRefundFullPrice = 1;
                if (order.postFee > 0) {
                    isRefundPostFee = 1;
                }
            }
            sql = 'update t_order_after_sale set status=1,affirm_by=?,affirm_by_id=?,affirm_source=1,affirm_time=NOW(),affirm_reason=?,is_refund_full_price=?,is_refund_post_fee=? where id=? ';
            const size3 = await this.executeSqlSucc(sql, [createBy, operatorId, $remark || '经核实，退回买家金额', isRefundFullPrice, isRefundPostFee, object.id], conn);
            if (size3 <= 0) {
                throw Error('更新退款记录失败')
            }


            let SELL = {
                isSendMessage: false,
                marginPrice: 0,
                marginPayMode: '',
                GETPrice: 0
            };
            let BUY = {
                isSendMessage: false,
                marginPrice: 0,
                marginPayMode: '',
                GETPrice: 0
            };

            let isBackMargin = false;
            let backMarginPrice = 0;
            let marginPayMode = '';
            let __sellerMargin = false;
            if (goods.goodsType === 1) {//如果是竞价商品 则退还保证金 / 扣除保证金

                if (!['BUYER', 'SELLER'].includes(deductOpposite)) {
                    //退还买家保证金
                    let buyMargin = await this.getBuyMargin(orderId, conn);
                    if (buyMargin) {
                        let buyResult = await this.backMargin(buyMargin, conn);
                        if (buyResult.code != 200) {
                            throw Error(buyResult.message)
                        } else {
                            isBackMargin = true;
                            backMarginPrice = buyMargin.price;
                            marginPayMode = buyMargin.payMode;
                        }
                    }
                } else {
                    if (deductOpposite === 'BUYER') {//扣除买家保证金 不退卖家保证金 竞拍商品下架
                        let buyMargin = await this.getBuyMargin(orderId, conn);
                        if (buyMargin) {
                            let buyResult = await this.forfeitMargin(buyMargin, orderId, 'buy', conn);
                            if (buyResult.code != 200) {
                                throw Error(buyResult.message)
                            } else {
                                BUY.isSendMessage = true;
                                BUY.marginPrice = buyMargin.price;
                                BUY.marginPayMode = buyMargin.payMode;
                                BUY.GETPrice = buyResult.GETPrice;
                            }
                        }
                    } else if (deductOpposite === 'SELLER') {//扣除卖家保证金 退买家保证金 竞拍商品下架
                        let sellMargin = await this.getSellMargin(goods.id, conn);
                        if (sellMargin) {
                            let sellResult = await this.forfeitMargin(sellMargin, orderId, 'sell', conn);
                            if (sellResult.code != 200) {
                                throw Error(sellResult.message)
                            } else {
                                SELL.isSendMessage = true;
                                SELL.marginPrice = sellMargin.price;
                                SELL.marginPayMode = sellMargin.payMode;
                                SELL.GETPrice = sellMargin.GETPrice;

                                __sellerMargin = true;
                            }
                        }

                        //退还买家保证金
                        let buyMargin = await this.getBuyMargin(orderId, conn);
                        if (buyMargin) {
                            let buyResult = await this.backMargin(buyMargin, conn);
                            if (buyResult.code != 200) {
                                throw Error(buyResult.message)
                            } else {
                                isBackMargin = true;
                                backMarginPrice = buyMargin.price;
                                marginPayMode = buyMargin.payMode;
                            }
                        }
                    }
                }

            }


            //商品数量更新
            sql = 'update t_shop_goods set sold_amount=0,status=9 where id=? ';
            if (goods.goodsType === 0 && !__sellerMargin) {
                sql = 'update t_shop_goods set sold_amount=0,status=1 where id=? ';
            }
            const size4 = await this.executeSqlSucc(sql, [goods.id], conn);
            if (size4 <= 0) {
                throw Error('商品数量更新失败')
            }

            let recordParams = {
                order_id: orderId,
                order_after_sale_id: object.id,
                status: 1,
                affirm_by: createBy,
                affirm_by_id: operatorId,
                affirm_source: 1
            };

            let insertResult = await this.executeInsert('t_order_after_sale_audit_record', recordParams, conn);
            if (!insertResult.affectedRows) {
                throw Error('添加退款审核记录失败');
            }

            if(orderAfterSale.refundReasonId === 'PriceAdj') {
                //当为补差价时 添加快递头数据。用于自动确认收货的时间依据
                let ticketParams = {
                    order_id: orderId,
                    company: 'PriceAdj',
                    ticket: 'C' + StringUtil.getUUID(),
                    last_status: 3,
                    valid: 1
                };
                let insertTicketResult = await this.executeInsert('t_order_ticket', ticketParams, conn);
                if (!insertTicketResult.affectedRows) {
                    throw Error('添加快递信息失败');
                }
            }

            //买家退款 因为有微信退款API 所以放到最后的逻辑
            //买家退款
            let changeParams2 = {
                userId: order.userId,
                amount: order.status === 1 ? sumPrice : order.payPrice,
                frozen: 0,
                wxOrderId: order['wxOrderId'],
                payMode: order['payMode'],
                aggRemark:order['aggRemark']
            };
            if (orderAfterSale.refundReasonId === 'PriceAdj') {//补差价金额 设置退款金额
                changeParams2.refundAmount = orderAfterSale.priceAdjAmount;
            }
            const bResult = await this.ctx.service.balance.backBalance(changeParams2, conn);
            if (bResult.code != 200) {
                throw Error('退款失败')
            }


            let buyOpenId = await this.getBuyOpenIdByOrderId(orderId);
            if (buyOpenId) {
                let messageParams = {
                    touser: buyOpenId,
                    goodsName: goods ? goods.name : '',
                    afterSaleType: '退货退款',
                    statusText: '商家已同意',
                    remark: '退款已处理，请注意查收',
                    page: '/pagesSub/pages/my-bought/my-bought?tab=4'
                };
                this.ctx.service.wechat.sendOrderAfterSaleMessage(messageParams);
            }

            //发送买家消息
            if (isBackMargin && buyOpenId) {
                let messageParams = {
                    touser: buyOpenId,
                    goodsName: goods.name,
                    amount: backMarginPrice + '元',
                    numberId: orderId,
                    remark: `退款商品，保证金已退回到【${this.ctx.MARGIN_MAP(marginPayMode)}】`,
                    page: '/pagesSub/pages/accounting/accounting?tab=1'
                };
                this.ctx.service.wechat.sendBackMarginMessage(messageParams);
            }

            //发送卖家消息
            let sellOpenId = await this.ctx.service.order.getSellOpenIdByOrderId(orderId);
            if (sellOpenId) {
                let messageParams = {
                    touser: sellOpenId,
                    amount: '-' + diffPrice + '元',
                    remark: `买家申请退款，退款成功`,
                    orderId: orderId,
                    changeType: '退款商品'
                };
                this.ctx.service.wechat.sendBalanceChangeMessage(messageParams);
            }

            if (SELL.isSendMessage) {
                //卖家发送 保证金扣除通知
                let sellUser = await this.ctx.service.user.selectPureByPrimaryKey(goods.userId);
                if (sellUser && sellUser.openid) {
                    let messageParams = {
                        touser: sellUser.openid,
                        goodsName: goods.name,
                        amount: SELL.marginPrice + '元',
                        remark: `退款，扣除保证金`,
                        page: '/pagesSub/pages/accounting/accounting?tab=2'
                    };
                    this.ctx.service.wechat.sendDeductMarginMessage(messageParams);
                }

            }
            if (BUY.isSendMessage) {
                //买家发送 保证金扣除通知
                let buyUser = await this.ctx.service.user.selectPureByPrimaryKey(order.userId);
                if (buyUser && buyUser.openid) {
                    let messageParams = {
                        touser: buyUser.openid,
                        goodsName: goods.name,
                        amount: BUY.marginPrice + '元',
                        remark: `申请退款，扣除保证金`,
                        page: '/pagesSub/pages/accounting/accounting?tab=2'
                    };
                    this.ctx.service.wechat.sendDeductMarginMessage(messageParams);
                }
            }

            await conn.commit();

            if (order.status === 3) {
                //异步更新商铺成交额
                this.ctx.service.user.updateShopTradeAmount(goods['userId'], -diffPrice);
            }

            return 1;
        } catch (e) {
            this.ctx.app.logger.error('orderConfirmRefund error', e.message);
            await conn.rollback();
            throw Error('系统错误，请稍后重试。')
        }
    }

    async getUserInfo(userId) {
        let sql = 'select * from t_user where id=? ';
        return await this.executeSqlFirst(sql, [userId]);
    }

    async getOrderChatList() {
        let {orderId, pageSize, pageNum} = this.ctx.query;
        let sql = `SELECT a.order_id,a.from_id,a.to_id,a.id,a.content,a.type,b.user_id as sell_user_id,IF(a.from_id=b.user_id,a.to_id,a.from_id) as buy_user_id FROM t_chat a INNER JOIN t_shop_goods b ON a.obj_id=b.id where (a.order_id=? or (a.obj_type='order' and a.obj_id=?) ) AND a.valid=1 `

        let options = [orderId, orderId];

        sql += " order by a.create_time desc ";
        sql = this.addMysqlPageSize(sql, pageNum, pageSize);
        let result = await this.queryPageData(sql, options);

        let list = result.list;

        await Promise.all(list.map(async (item) => {
            let sellUser = await this.getUserInfo(item.sellUserId);
            item.sellUserName = sellUser ? sellUser.name : '';
            item.sellUserAvatar = sellUser ? sellUser.avatarUrl : '';
            let buyUser = await this.getUserInfo(item.buyUserId);
            item.buyUserName = buyUser ? buyUser.name : '';
            item.buyUserAvatar = buyUser ? buyUser.avatarUrl : '';
        }));

        return result;

    }


    async orderForceRefund() {
        let {orderId, deductOpposite, isPriceAdj, priceAdjAmount, isRefundPostFee = 1} = this.ctx.request.body;

        let loginUserInfo = this.ctx.getLoginInfo();
        let operatorType = loginUserInfo.operatorType;
        let operatorId = loginUserInfo.operatorId;
        let createBy = loginUserInfo.createBy;

        if (!orderId) {
            return ResponseUtil.retArgErr();
        }


        let sql = 'select * from t_order_after_sale where order_id=? and status=1';
        let object = await this.executeSqlFirst(sql, [orderId]);
        if (object) {
            return ResponseUtil.resError('该订单已经退款过了');
        }

        let order = await this.selectPureByPrimaryKey(orderId);
        if (!order || order.valid === 0 || order.delFlag === 1) {
            return ResponseUtil.resError(VRCE.ORDER_NOT_EXIST[1], VRCE.ORDER_NOT_EXIST[1]);
        }

        if (![1, 2, 3].includes(order.status)) {
            return ResponseUtil.resError(VRCE.ORDER_UNPAY[1], VRCE.ORDER_UNPAY[0]);
        }

        let goods = await this.ctx.service.goods.selectPureByPrimaryKey(order.goodsId);
        if (!goods) {
            return ResponseUtil.resError(VRCE.NOT_EXIST_GOODS[1], VRCE.NOT_EXIST_GOODS[0]);
        }

        if (goods.goodsType == 1) {
            if (!['SELLER', 'BUYER', 'NONE'].includes(deductOpposite)) {
                return ResponseUtil.resError('deductOpposite is require');
            }
        }

        let conn = await this.app.mysql.beginTransaction();

        try {
            //退款申请对象查询判断 更新退款申请
            //减去卖家冻结 强制退款扣快递费??
            //返回买家金额 强制退款退快递费??
            //买/卖家资金详情
            //资金详情状态更改
            //退买家保证金
            //商品数量更新
            //扣除卖家保证金??
            //买家瓜分保证金??

            let orderAfterSaleId = 0;
            let sql0 = 'select * from t_order_after_sale where order_id=? and user_id=? and status=0 ';
            let orderAfter = await this.executeSqlFirst(sql0, [orderId, order.userId], conn);
            let Price = HelperUtil.bigNumberPlus(order['payPrice'], order['postFee']);
            if (isRefundPostFee != 1) {
                Price = order['payPrice'];
            }
            if (orderAfter) {
                let sql = 'update t_order_after_sale set is_force=1,remark=?,affirm_by=?,affirm_by_id=?,affirm_source=?,affirm_time=?,affirm_reason=?,price=?,is_refund_full_price=1,is_refund_post_fee=1 where id = ?';
                let size = await this.executeSqlSucc(sql, ['admin force refund', createBy, operatorId, 1, new Date, '卖家存在违规/发货与实物不匹配', Price, orderAfter.id], conn);
                if (size <= 0) {
                    throw Error('更新申请信息失败')
                }
                orderAfterSaleId = orderAfter.id;
            } else {
                let params = {
                    id: StringUtil.getUUIDV2(),
                    order_id: orderId,
                    user_id: order.userId,
                    reason: '卖家存在违规/发货与实物不匹配',
                    status: 1,
                    price: Price,
                    affirm_by: createBy,
                    affirm_by_id: operatorId,
                    affirm_source: 1,
                    affirm_time: new Date(),
                    affirm_reason: '卖家存在违规/发货与实物不匹配',
                    is_force: 1,
                    remark: 'admin force refund && add data',
                    is_refund_full_price: 1,
                    is_refund_post_fee: 1
                };
                let insertResult = await this.executeInsert('t_order_after_sale', params, conn);
                if (!insertResult.affectedRows) {
                    throw Error('添加申请信息失败')
                }
                orderAfterSaleId = insertResult.insertId;
            }


            const payPrice = order.payPrice;
            const postFee = order.postFee;
            const sumPrice = Price;
            let diffPrice = order.deliverGoodsMode == 1 ? HelperUtil.bigNumberMinus(order['curSellPrice'], postFee) : order['curSellPrice'];//不退快递费
            if (isRefundPostFee == 1) {//退快递费
                diffPrice = order['curSellPrice']
            }

            if (diffPrice < 0) {
                throw Error('退款金额异常')
            }

            //减去卖家冻结
            if (order.status === 3) {
                let changeParams = {
                    userId: goods.userId, amount: -diffPrice, frozen: 0
                };
                const size = await this.ctx.service.balance.changeBalance(changeParams, conn);
                if (size <= 0) {
                    throw Error('更新卖家余额失败，可能余额不足')
                }
            } else {
                let changeParams = {
                    userId: goods.userId, amount: 0, frozen: -diffPrice
                };
                const size = await this.ctx.service.balance.changeBalance(changeParams, conn);
                if (size <= 0) {
                    throw Error('更新卖家余额失败，可能余额不足')
                }

                if (order.deliverGoodsMode == 1 && isRefundPostFee != 1) {
                    //当为冻结时 将快递非从冻结转化成可用
                    let changeParams2 = {
                        userId: goods.userId, amount: postFee, frozen: -postFee
                    };
                    const size2 = await this.ctx.service.balance.changeBalance(changeParams2, conn);
                    if (size2 <= 0) {
                        throw Error('更新卖家余额失败，可能余额不足')
                    }
                }

            }


            //卖家资金详情
            let sellBalanceParams = {
                userId: goods.userId,
                type: goods.goodsType === 1 ? BalanceDetailType.ORDER_BIDDING[0] : BalanceDetailType.ORDER_BUYNOW[0],
                typeRemark: goods.goodsType === 1 ? BalanceDetailType.ORDER_BIDDING[1] : BalanceDetailType.ORDER_BUYNOW[1],
                balanceRemark: '买家商品退款成功',
                tranType: 'out',
                payMode: PayMode.BALANCE,
                amount: diffPrice,
                feeRate: 0,
                feeAmount: 0,
                totalAmount: diffPrice,
                refId: orderId,
                status: 1
            };
            let size = await this.ctx.service.balance.insertBalanceDetail(sellBalanceParams, conn);
            if (size <= 0) {
                throw Error('插入资金详情记录失败')
            }


            //买家资金详情
            let buyBalanceParams = {
                userId: order.userId,
                type: goods.goodsType === 1 ? BalanceDetailType.ORDER_BIDDING[0] : BalanceDetailType.ORDER_BUYNOW[0],
                typeRemark: goods.goodsType === 1 ? BalanceDetailType.ORDER_BIDDING[1] : BalanceDetailType.ORDER_BUYNOW[1],
                balanceRemark: '商品退款成功',
                tranType: 'in',
                payMode: order.payMode,
                amount: sumPrice,
                feeRate: 0,
                feeAmount: 0,
                totalAmount: sumPrice,
                refId: orderId,
                status: 1
            };
            size = await this.ctx.service.balance.insertBalanceDetail(buyBalanceParams, conn);
            if (size <= 0) {
                throw Error('插入资金详情记录失败')
            }


            //资金详情状态更改 卖家与买家
            let sql = 'select * from t_balance_detail where ref_id=? and (type="order_buynow" or type="order_bidding")';
            let detailList = await this.executeSql(sql, [orderId], conn);
            for (let i = 0; i < detailList.length; i++) {
                let sql = 'update t_balance_detail set status=2 where id=?';
                let size = await this.executeSqlSucc(sql, [detailList[i].id], conn);
                if (size <= 0) {
                    throw Error('更改资金记录失败')
                }
            }


            let SELL = {
                isSendMessage: false,
                marginPrice: 0,
                marginPayMode: '',
                GETPrice: 0
            };
            let BUY = {
                isSendMessage: false,
                marginPrice: 0,
                marginPayMode: '',
                GETPrice: 0
            };

            let isBackMargin = false;
            let backMarginPrice = 0;
            let marginPayMode = '';
            let __sellerMargin = false;


            if (goods.goodsType === 1) {//如果是竞价商品 则退还保证金 / 扣除保证金
                if (!['BUYER', 'SELLER'].includes(deductOpposite)) {
                    //退还买家保证金
                    let buyMargin = await this.getBuyMargin(orderId, conn);
                    if (buyMargin) {
                        let buyResult = await this.backMargin(buyMargin, conn);
                        if (buyResult.code != 200) {
                            throw Error(buyResult.message)
                        } else {
                            isBackMargin = true;
                            backMarginPrice = buyMargin.price;
                            marginPayMode = buyMargin.payMode;
                        }
                    }
                } else {
                    if (deductOpposite === 'BUYER') {//扣除买家保证金 不退卖家保证金 竞拍商品下架
                        let buyMargin = await this.getBuyMargin(orderId, conn);
                        if (buyMargin) {
                            let buyResult = await this.forfeitMargin(buyMargin, orderId, 'buy', conn);
                            if (buyResult.code != 200) {
                                throw Error(buyResult.message)
                            } else {
                                BUY.isSendMessage = true;
                                BUY.marginPrice = buyMargin.price;
                                BUY.marginPayMode = buyMargin.payMode;
                                BUY.GETPrice = buyResult.GETPrice;
                            }
                        }
                    } else if (deductOpposite === 'SELLER') {//扣除卖家保证金 退买家保证金 竞拍商品下架
                        let sellMargin = await this.getSellMargin(goods.id, conn);
                        if (sellMargin) {
                            let sellResult = await this.forfeitMargin(sellMargin, orderId, 'sell', conn);
                            if (sellResult.code != 200) {
                                throw Error(sellResult.message)
                            } else {
                                SELL.isSendMessage = true;
                                SELL.marginPrice = sellMargin.price;
                                SELL.marginPayMode = sellMargin.payMode;
                                SELL.GETPrice = sellMargin.GETPrice;

                                __sellerMargin = true;
                            }
                        }

                        //退还买家保证金
                        let buyMargin = await this.getBuyMargin(orderId, conn);
                        if (buyMargin) {
                            let buyResult = await this.backMargin(buyMargin, conn);
                            if (buyResult.code != 200) {
                                throw Error(buyResult.message)
                            } else {
                                isBackMargin = true;
                                backMarginPrice = buyMargin.price;
                                marginPayMode = buyMargin.payMode;
                            }
                        }
                    }
                }

            }


            //商品数量更新
            sql = 'update t_shop_goods set sold_amount=0,status=9 where id=? ';
            if (goods.goodsType === 0 && !__sellerMargin) {
                sql = 'update t_shop_goods set sold_amount=0,status=1 where id=? ';
            }
            const size4 = await this.executeSqlSucc(sql, [goods.id], conn);
            if (size4 <= 0) {
                throw Error('商品数量更新失败')
            }

            let recordParams = {
                order_id: orderId,
                order_after_sale_id: orderAfterSaleId,
                status: 1,
                affirm_by: createBy,
                affirm_by_id: operatorId,
                affirm_source: 1
            };

            let insertResult = await this.executeInsert('t_order_after_sale_audit_record', recordParams, conn);
            if (!insertResult.affectedRows) {
                throw Error('添加退款审核记录失败');
            }

            //买家退款
            let changeParams2 = {
                userId: order.userId,
                amount: HelperUtil.bigNumberPlus(order['payPrice'], order['postFee']),
                refundAmount: sumPrice,
                frozen: 0,
                wxOrderId: order['wxOrderId'],
                payMode: order['payMode'],
                aggRemark:order['aggRemark']
            };
            const bResult = await this.ctx.service.balance.backBalance(changeParams2, conn);
            if (bResult.code != 200) {
                throw Error('退款失败')
            }


            let buyOpenId = await this.getBuyOpenIdByOrderId(orderId);
            if (buyOpenId) {
                let messageParams = {
                    touser: buyOpenId,
                    goodsName: goods ? goods.name : '',
                    afterSaleType: '退货退款',
                    statusText: '商家已同意',
                    remark: '退款已处理，请注意查收',
                    page: '/pagesSub/pages/my-bought/my-bought?tab=4'
                };
                this.ctx.service.wechat.sendOrderAfterSaleMessage(messageParams);
            }

            //发送买家消息
            if (isBackMargin && buyOpenId) {
                let messageParams = {
                    touser: buyOpenId,
                    goodsName: goods.name,
                    amount: backMarginPrice + '元',
                    numberId: orderId,
                    remark: `退款商品，保证金已退回到【${this.ctx.MARGIN_MAP(marginPayMode)}】`,
                    page: '/pagesSub/pages/accounting/accounting?tab=1'
                };
                this.ctx.service.wechat.sendBackMarginMessage(messageParams);
            }

            //发送卖家消息
            let sellOpenId = await this.ctx.service.order.getSellOpenIdByOrderId(orderId);
            if (sellOpenId) {
                let messageParams = {
                    touser: sellOpenId,
                    amount: '-' + order['curSellPrice'] + '元',
                    remark: `买家退款，退款成功`,
                    orderId: orderId,
                    changeType: '退款商品'
                };
                this.ctx.service.wechat.sendBalanceChangeMessage(messageParams);
            }

            if (SELL.isSendMessage) {
                //卖家发送 保证金扣除通知
                let sellUser = await this.ctx.service.user.selectPureByPrimaryKey(goods.userId);
                if (sellUser && sellUser.openid) {
                    let messageParams = {
                        touser: sellUser.openid,
                        goodsName: goods.name,
                        amount: SELL.marginPrice + '元',
                        remark: `退款，扣除保证金`,
                        page: '/pagesSub/pages/accounting/accounting?tab=2'
                    };
                    this.ctx.service.wechat.sendDeductMarginMessage(messageParams);
                }

            }
            if (BUY.isSendMessage) {
                //买家发送 保证金扣除通知
                let buyUser = await this.ctx.service.user.selectPureByPrimaryKey(order.userId);
                if (buyUser && buyUser.openid) {
                    let messageParams = {
                        touser: buyUser.openid,
                        goodsName: goods.name,
                        amount: BUY.marginPrice + '元',
                        remark: `申请退款，扣除保证金`,
                        page: '/pagesSub/pages/accounting/accounting?tab=2'
                    };
                    this.ctx.service.wechat.sendDeductMarginMessage(messageParams);
                }
            }

            await conn.commit();

            if (order.status === 3) {
                //异步更新商铺成交额
                this.ctx.service.user.updateShopTradeAmount(goods['userId'], -order['curSellPrice']);
            }

            return 1;
        } catch (e) {
            this.ctx.app.logger.error('orderForceRefund error', e.message);
            await conn.rollback();
            throw Error('系统错误，请稍后重试。')
        }
    }

}

module.exports = OrderService;
